package cn.parus.dynamicRouter.dao.Repository.impl;

import cn.parus.commons.utils.GenericCacheUtil;
import cn.parus.commons.utils.GenericRedisUtil;
import cn.parus.commons.utils.TimeoutUtil;
import cn.parus.dynamicRouter.dao.Repository.ApiRepository;
import cn.parus.dynamicRouter.entity.ApiInfo;
import cn.parus.dynamicRouter.mapper.ApiMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * @Author: Axel
 * @Description: TODO 核心数据库用mysql来实现，未来会转为openGauss实现
 * redis穿透保护
 * redis雪崩保护
 **/
@Repository
public class MySQLApiRepository implements ApiRepository {

    // 缓存总key
    private static final String CACHE_KEY = "api-router";
    private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS;
    private static final Logger log = LoggerFactory.getLogger(MySQLApiRepository.class);

    /**
     * 通过final字段让apiMapper字段只在构造函数中初始化一次
     * 并且通过控制反转将ApiMapper实例注入到该类中
     */
    private final ApiMapper apiMapper;
    private final GenericCacheUtil genericCacheUtil;
    private final GenericRedisUtil genericRedisUtil;
    @Autowired
    public MySQLApiRepository(ApiMapper apiMapper, GenericCacheUtil genericCacheUtil, GenericRedisUtil genericRedisUtil) {
        this.apiMapper = apiMapper;
        this.genericCacheUtil = genericCacheUtil;
        this.genericRedisUtil = genericRedisUtil;
    }

    /**
     * 查询所有，用于全局刷新路由
     * 当前路由刷新使用全量刷新
     * @return
     */
    @Override
    public List<ApiInfo> getAll() {
        return genericCacheUtil.cacheable(CACHE_KEY + ":all",
                new TypeReference<List<ApiInfo>>() {},
                () -> apiMapper.getAll(),
                TimeoutUtil.getRandomExpire(3600),
                TIME_UNIT);
    }

    /**
     * 用于首页交互,分页查询，后端分页，数据库不分页
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<ApiInfo> getAll(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<ApiInfo> list = genericCacheUtil.cacheable(CACHE_KEY + ":all",
                new TypeReference<List<ApiInfo>>() {},
                () -> apiMapper.getAll(),
                TimeoutUtil.getRandomExpire(3600),
                TIME_UNIT);
        return PageInfo.of(list);
    }

    /**
     * 根据serviceId进行查询
     * @param serviceId
     * @return
     */
    @Override
    public List<ApiInfo> getServiceById(String serviceId) {
        return genericCacheUtil.hcacheable(
                CACHE_KEY + ":item",
                serviceId,
                new TypeReference<List<ApiInfo>>() {},
                () -> apiMapper.getByServiceId(serviceId),
                TimeoutUtil.getRandomExpire(3600),
                TIME_UNIT
        );
    }

    /**
     * 更新/删除
     * @param apiInfo
     */
    @Override
    public void save(ApiInfo apiInfo) {
        try {
            if(apiMapper.getById(apiInfo.getId()) == null) {
                apiMapper.insert(apiInfo);
            } else {
                String value = apiMapper.getById(apiInfo.getId()).getServiceId();
                if(value != null && !value.isEmpty()) {
                    genericRedisUtil.hdelete(CACHE_KEY + ":item", value);
                };
                apiMapper.update(apiInfo);
            }
            // 更新后清除相关缓存
            genericRedisUtil.delete(CACHE_KEY + ":all");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据id删除路由
     * @param id
     */
    @Override
    public void delete(String id) {
        try {
            genericRedisUtil.delete(CACHE_KEY + ":all");
            String value = apiMapper.getById(id).getServiceId();
            if(value != null && !value.isEmpty()) {
                genericRedisUtil.hdelete(CACHE_KEY + ":item", value);
            };
            apiMapper.delete(id);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
